package sicnu.cs.ich.security.security.rest;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import sicnu.cs.ich.api.common.Constants;
import sicnu.cs.ich.common.services.impl.RedisService;
import sicnu.cs.ich.common.util.keyCryptor.AESUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
@RequiredArgsConstructor
@RefreshScope
public class RestAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final RedisService redisService;
    private final ObjectMapper objectMapper;

    @Value("${ich.decrypt.enabled}")
    private Boolean decryptOpen;


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try (InputStream inputStream = request.getInputStream()) {
            JsonNode jsonNode;
            if (decryptOpen) {
                String encodeBody = new String(inputStream.readAllBytes());
                String decode = AESUtil.decode((String) redisService.getValue(Constants.REDIS_AES_KEY), encodeBody);
                jsonNode = objectMapper.readTree(decode);
            } else {
                jsonNode = objectMapper.readTree(inputStream);
            }
            if (!jsonNode.has(Constants.LOGIN_NAME) || !jsonNode.has(Constants.LOGIN_PASSWORD)) {
                throw new BadCredentialsException("用户名参数不正确");
            }
            val username = jsonNode.get("username").textValue();
            val password = jsonNode.get("password").textValue();
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
            setDetails(request, token);
            return this.getAuthenticationManager().authenticate(token);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BadCredentialsException("没有找到或密码参数");
        }
    }
}
